

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/fluid.png">
  <link rel="icon" href="/img/fluid.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="czr">
  <meta name="keywords" content="">
  
    <meta name="description" content="jwt token工具类编写 生成token 验证token是否有效 判断token是否过期 判断token是否可以被刷新 刷新token  定义工具类123456789public class JwtTokenUtil &amp;#123;    private static final String CLAIM_KEY_USERNAME &#x3D; &quot;sub&quot;;    private st">
<meta property="og:type" content="article">
<meta property="og:title" content="认证授权">
<meta property="og:url" content="http://czrgitee.gitee.io/2023/05/23/%E8%AE%A4%E8%AF%81%E6%8E%88%E6%9D%83/index.html">
<meta property="og:site_name" content="安徒生">
<meta property="og:description" content="jwt token工具类编写 生成token 验证token是否有效 判断token是否过期 判断token是否可以被刷新 刷新token  定义工具类123456789public class JwtTokenUtil &amp;#123;    private static final String CLAIM_KEY_USERNAME &#x3D; &quot;sub&quot;;    private st">
<meta property="og:locale" content="zh_CN">
<meta property="article:published_time" content="2023-05-23T07:36:02.000Z">
<meta property="article:modified_time" content="2023-06-06T08:42:34.367Z">
<meta property="article:author" content="czr">
<meta property="article:tag" content="yeb">
<meta name="twitter:card" content="summary_large_image">
  
  
  
  <title>认证授权 - 安徒生</title>

  <link  rel="stylesheet" href="https://lib.baomitu.com/twitter-bootstrap/4.6.1/css/bootstrap.min.css" />



  <link  rel="stylesheet" href="https://lib.baomitu.com/github-markdown-css/4.0.0/github-markdown.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/hint.css/2.7.0/hint.min.css" />

  <link  rel="stylesheet" href="https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.css" />



<!-- 主题依赖的图标库，不要自行修改 -->
<!-- Do not modify the link that theme dependent icons -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_hj8rtnfg7um.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />


  <link id="highlight-css" rel="stylesheet" href="/css/highlight.css" />
  
    <link id="highlight-css-dark" rel="stylesheet" href="/css/highlight-dark.css" />
  



  
<link rel="stylesheet" href="/css/macpanel.css">



  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    Fluid.ctx = Object.assign({}, Fluid.ctx)
    var CONFIG = {"hostname":"czrgitee.gitee.io","root":"/","version":"1.9.0","typing":{"enable":true,"typeSpeed":120,"cursorChar":"_","loop":false,"scope":[]},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"left","visible":"hover","icon":""},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"code_language":{"enable":true,"default":"TEXT"},"copy_btn":true,"image_caption":{"enable":true},"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"placement":"right","headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":1},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":false,"offset_factor":2},"web_analytics":{"enable":false,"follow_dnt":true,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};

    if (CONFIG.web_analytics.follow_dnt) {
      var dntVal = navigator.doNotTrack || window.doNotTrack || navigator.msDoNotTrack;
      Fluid.ctx.dnt = dntVal && (dntVal.startsWith('1') || dntVal.startsWith('yes') || dntVal.startsWith('on'));
    }
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
  


  
<meta name="generator" content="Hexo 6.3.0"></head>


<body>
  

  <header>
    

<div class="header-inner" style="height: 70vh;">
  <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>Andersen</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                <span>首页</span>
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                <span>归档</span>
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              <i class="iconfont icon-search"></i>
            </a>
          </li>
          
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">
              <i class="iconfont icon-dark" id="color-toggle-icon"></i>
            </a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

  

<div id="banner" class="banner" parallax=true
     style="background: url('https://tuapi.eees.cc/api.php?category=fengjing&type=302') no-repeat center center; background-size: cover;">
  <div class="full-bg-img">
    <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
      <div class="banner-text text-center fade-in-up">
        <div class="h2">
          
            <span id="subtitle" data-typed-text="认证授权"></span>
          
        </div>

        
          
  <div class="mt-3">
    
    
      <span class="post-meta">
        <i class="iconfont icon-date-fill" aria-hidden="true"></i>
        <time datetime="2023-05-23 15:36" pubdate>
          2023年5月23日 下午
        </time>
      </span>
    
  </div>

  <div class="mt-1">
    
      <span class="post-meta mr-2">
        <i class="iconfont icon-chart"></i>
        
          28k 字
        
      </span>
    

    
      <span class="post-meta mr-2">
        <i class="iconfont icon-clock-fill"></i>
        
        
        
          236 分钟
        
      </span>
    

    
    
  </div>


        
      </div>

      
    </div>
  </div>
</div>

</div>

  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="side-col d-none d-lg-block col-lg-2">
      

    </div>

    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">认证授权</h1>
            
              <p class="note note-info">
                
                  
                    本文最后更新于：2023年6月6日 下午
                  
                
              </p>
            
            
              <div class="markdown-body">
                
                <h2 id="jwt-token工具类编写"><a href="#jwt-token工具类编写" class="headerlink" title="jwt token工具类编写"></a>jwt token工具类编写</h2><ul>
<li>生成token</li>
<li>验证token是否有效</li>
<li>判断token是否过期</li>
<li>判断token是否可以被刷新</li>
<li>刷新token</li>
</ul>
<h4 id="定义工具类"><a href="#定义工具类" class="headerlink" title="定义工具类"></a>定义工具类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">JwtTokenUtil</span> &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">CLAIM_KEY_USERNAME</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;sub&quot;</span>;<br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">String</span> <span class="hljs-variable">CLAIM_KEY_CREATED</span> <span class="hljs-operator">=</span> <span class="hljs-string">&quot;created&quot;</span>;<br>    <span class="hljs-meta">@Value(&quot;$&#123;jwt.secret&#125;&quot;)</span><br>    <span class="hljs-keyword">private</span> String secret;<br>    <span class="hljs-meta">@Value(&quot;$&#123;jwt.expiration&#125;&quot;)</span><br>    <span class="hljs-keyword">private</span> Long expiration;<br><br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="生成token"><a href="#生成token" class="headerlink" title="生成token"></a>生成token</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 根据用户信息生成token</span><br><span class="hljs-comment"> * 这段代码是一个生成jwt token的方法，它接受一个UserDetails对象作为参数。</span><br><span class="hljs-comment"> * 在该方法中，首先创建了一个Map对象claims，用于存储token中的payload部分（包含用户信息和其他自定义数据）。</span><br><span class="hljs-comment"> * 然后将用户名和当前时间加入到claims中。</span><br><span class="hljs-comment"> * 最后调用generateToken()方法，将claims作为参数传入，返回一个生成的jwt token。</span><br><span class="hljs-comment"> * 具体generateToken()方法的实现可能需要查看代码其他部分</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> userDetails</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> String <span class="hljs-title function_">generateToken</span><span class="hljs-params">(UserDetails userDetails)</span> &#123;<br>    Map&lt;String, Object&gt; claims = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;();<br>    claims.put(CLAIM_KEY_USERNAME, userDetails.getUsername());<br>    claims.put(CLAIM_KEY_CREATED, <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>());<br>    <span class="hljs-keyword">return</span> generateToken(claims);<br>&#125;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 根据负载生成JWT Token</span><br><span class="hljs-comment"> * 在这段代码中，首先调用Jwts.builder()方法创建一个JwtBuilder对象，然后使用setClaims()方法将传入的claims设置到该JwtBuilder对象中。</span><br><span class="hljs-comment"> * 接着调用setExpiration()方法设置Token的过期时间，generateExpirationDate()方法应该是用于计算过期时间的辅助方法。</span><br><span class="hljs-comment"> * 最后，使用signWith()方法指定签名算法和密钥进行签名，并调用compact()方法生成Token。</span><br><span class="hljs-comment"> * 需要注意的是，这里使用了HS512算法进行签名，这是一种比较新的、基于椭圆曲线的数字签名算法。</span><br><span class="hljs-comment"> * 同时，secret变量应该是存储在服务器端的一个私密密钥，用于对Token进行签名和验证。</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> claims</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">private</span> String <span class="hljs-title function_">generateToken</span><span class="hljs-params">(Map&lt;String, Object&gt; claims)</span> &#123;<br>    <span class="hljs-keyword">return</span> Jwts.builder()<br>            .setClaims(claims)  <span class="hljs-comment">//使用setClaims()方法将传入的claims设置到该JwtBuilder对象中</span><br>            .setExpiration(generateExpirationDate())  <span class="hljs-comment">//调用setExpiration()方法设置Token的过期时间</span><br>            .signWith(SignatureAlgorithm.HS512, secret)<br>            .compact();<br>&#125;<br><br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 生成token过期时间</span><br><span class="hljs-comment"> * 这段代码是用于生成JWT Token的过期时间的辅助方法，它返回一个Date对象，该对象表示当前时间加上过期时间。</span><br><span class="hljs-comment"> * 在这个方法中，通过调用System.currentTimeMillis()获取当前时间的毫秒数，然后加上expiration（以秒为单位）乘以1000的结果，得到Token的过期时间。</span><br><span class="hljs-comment"> * 最后，将该时间转换成Date对象并返回。</span><br><span class="hljs-comment"> * 需要注意的是，这里使用了System.currentTimeMillis()方法获取当前时间，这种方式获取的时间是相对于1970年1月1日00:00:00 UTC的毫秒数。</span><br><span class="hljs-comment"> * 而expiration变量应该是以秒为单位的整数，因此需要将其乘以1000转换为毫秒。</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">private</span> Date <span class="hljs-title function_">generateExpirationDate</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>(System.currentTimeMillis() + expiration * <span class="hljs-number">1000</span>);<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="验证token是否有效"><a href="#验证token是否有效" class="headerlink" title="验证token是否有效"></a>验证token是否有效</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 验证token是否有效</span><br><span class="hljs-comment">     * 这是一个用于验证token是否有效的方法。该方法接收两个参数：token和userDetails对象，</span><br><span class="hljs-comment">     * 其中，token是用户请求时传递的令牌，而userDetails则是表示已认证的用户详细信息的对象。</span><br><span class="hljs-comment">     * &lt;p&gt;</span><br><span class="hljs-comment">     * 该方法首先调用getUserNameFormToken方法从token中解析出用户名，然后将解析出的用户名与userDetails对象中的用户名进行比较，</span><br><span class="hljs-comment">     * 如果两者相同，则说明该token是有效的。</span><br><span class="hljs-comment">     * 同时，该方法还会调用isTokenExpired方法来检查token是否过期，如果token已经过期，则该方法也会返回false。</span><br><span class="hljs-comment">     * &lt;p&gt;</span><br><span class="hljs-comment">     * 最终，如果token有效且未过期，则该方法返回true，否则返回false。</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> token</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> userDetails</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">validateToken</span><span class="hljs-params">(String token, UserDetails userDetails)</span> &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">username</span> <span class="hljs-operator">=</span> getUserNameFormToken(token);<br>        <span class="hljs-keyword">return</span> username.equals(userDetails.getUsername()) &amp;&amp;<br>                !isTokenExpired(token);<br>    &#125;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 从token中获取登录用户名</span><br><span class="hljs-comment">     * 这段代码是一个获取JWT令牌中的用户名的方法。</span><br><span class="hljs-comment">     * 其中，参数token是JWT令牌字符串，方法内部调用了getClaimsFromToken(token)方法来解析JWT令牌，并从中获取用户名信息。</span><br><span class="hljs-comment">     * 如果解析失败或者用户名为空，则返回null。具体实现需要依赖于相应的JWT库或者自己手动解析JWT令牌。</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> token</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> String <span class="hljs-title function_">getUserNameFormToken</span><span class="hljs-params">(String token)</span> &#123;<br>        String username;<br>        <span class="hljs-keyword">try</span> &#123;<br>            <span class="hljs-type">Claims</span> <span class="hljs-variable">claims</span> <span class="hljs-operator">=</span> getClaimsFromToken(token);<br>            username = claims.getSubject();<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            username = <span class="hljs-literal">null</span>;<br>        &#125;<br>        <span class="hljs-keyword">return</span> username;<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 从token中获取JWT中的负载</span><br><span class="hljs-comment">     * 这段代码通过 Jwts.parser() 创建一个 JWT 解析器对象，并设置签名密钥为 secret（即用于生成和验证 JWT Token 的密钥）。</span><br><span class="hljs-comment">     * 然后使用 parseClaimsJws() 方法解析传入的 token 字符串，并调用 getBody() 方法获取其中的 Claims 对象。</span><br><span class="hljs-comment">     * 如果解析过程中发生异常，则将其打印并返回 null。</span><br><span class="hljs-comment">     * 最终，该方法返回解析出的 Claims 对象，以便其他业务逻辑使用其中的用户信息</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> token</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> Claims <span class="hljs-title function_">getClaimsFromToken</span><span class="hljs-params">(String token)</span> &#123;<br>        <span class="hljs-type">Claims</span> <span class="hljs-variable">claims</span> <span class="hljs-operator">=</span> <span class="hljs-literal">null</span>;<br>        <span class="hljs-keyword">try</span> &#123;<br>            claims = Jwts.parser()<br>                    .setSigningKey(secret)<br>                    .parseClaimsJws(token)<br>                    .getBody();<br>        &#125; <span class="hljs-keyword">catch</span> (Exception e) &#123;<br>            e.printStackTrace();<br>        &#125;<br>        <span class="hljs-keyword">return</span> claims;<br>    &#125;<br></code></pre></td></tr></table></figure>

<h4 id="判断token是否失效"><a href="#判断token是否失效" class="headerlink" title="判断token是否失效"></a>判断token是否失效</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 判断token是否失效</span><br><span class="hljs-comment"> * 这段代码实现了判断一个令牌（token）是否已经过期的功能。</span><br><span class="hljs-comment"> * 它通过调用 getExpiredDateFromToken() 方法获取该 token 的失效时间，然后使用 before() 方法判断该时间是否在当前时间之前。</span><br><span class="hljs-comment"> * 如果是，说明该 token 已经过期，返回 true；否则返回 false。</span><br><span class="hljs-comment"> * &lt;p&gt;</span><br><span class="hljs-comment"> * 需要注意的是，这里使用了 Java 中的 Date 类型，表示一个日期和时间。before() 方法是 Date 类中的一个比较方法，用于比较两个日期的先后顺序。</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> token</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">private</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">isTokenExpired</span><span class="hljs-params">(String token)</span> &#123;<br>    <span class="hljs-type">Date</span> <span class="hljs-variable">expiredDate</span> <span class="hljs-operator">=</span> getExpiredDateFromToken(token);  <span class="hljs-comment">//获取失效时间</span><br>    <span class="hljs-keyword">return</span> expiredDate.before(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>());  <span class="hljs-comment">//判断是否在当前时间前</span><br>&#125;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 从token中获取过期时间*</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> token</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">private</span> Date <span class="hljs-title function_">getExpiredDateFromToken</span><span class="hljs-params">(String token)</span> &#123;<br>    <span class="hljs-type">Claims</span> <span class="hljs-variable">claims</span> <span class="hljs-operator">=</span> getClaimsFromToken(token);<br>    <span class="hljs-keyword">return</span> claims.getExpiration();<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="判断token是否可以被刷新"><a href="#判断token是否可以被刷新" class="headerlink" title="判断token是否可以被刷新"></a>判断token是否可以被刷新</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 判断token是否可以被刷新</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> token</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">canRefresh</span><span class="hljs-params">(String token)</span> &#123;<br>    <span class="hljs-keyword">return</span> !isTokenExpired(token);<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="刷新token"><a href="#刷新token" class="headerlink" title="刷新token"></a>刷新token</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 刷新token</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> token</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> String <span class="hljs-title function_">refreshToken</span><span class="hljs-params">(String token)</span> &#123;<br>    <span class="hljs-type">Claims</span> <span class="hljs-variable">claims</span> <span class="hljs-operator">=</span> getClaimsFromToken(token);  <span class="hljs-comment">//从token中获取荷载信息</span><br>    claims.put(CLAIM_KEY_CREATED, <span class="hljs-keyword">new</span> <span class="hljs-title class_">Date</span>());  <span class="hljs-comment">//放入当前时间</span><br>    <span class="hljs-keyword">return</span> generateToken(claims);  <span class="hljs-comment">//根据负载生成JWT Token</span><br>&#125;<br></code></pre></td></tr></table></figure>

<hr>
<h2 id="公共返回对象"><a href="#公共返回对象" class="headerlink" title="公共返回对象"></a>公共返回对象</h2><ul>
<li>状态码</li>
<li>message</li>
<li>数据对象</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Data</span>  <span class="hljs-comment">//get/set方法</span><br><span class="hljs-meta">@NoArgsConstructor</span>  <span class="hljs-comment">//无参构造方法</span><br><span class="hljs-meta">@AllArgsConstructor</span>  <span class="hljs-comment">//有参构造方法</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">RspBean</span> &#123;<br>    <span class="hljs-keyword">private</span> <span class="hljs-type">long</span> code;<br>    <span class="hljs-keyword">private</span> String message;<br>    <span class="hljs-keyword">private</span> Object data;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 成功返回</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> message</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> RspBean <span class="hljs-title function_">success</span><span class="hljs-params">(String message)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RspBean</span>(<span class="hljs-number">200</span>, message, <span class="hljs-literal">null</span>);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 成功返回</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> message</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> data</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> RspBean <span class="hljs-title function_">success</span><span class="hljs-params">(String message, Object data)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RspBean</span>(<span class="hljs-number">200</span>, message, data);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 失败返回</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> message</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> RspBean <span class="hljs-title function_">error</span><span class="hljs-params">(String message)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RspBean</span>(<span class="hljs-number">500</span>, message, <span class="hljs-literal">null</span>);<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 失败返回</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> message</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> data</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> RspBean <span class="hljs-title function_">error</span><span class="hljs-params">(String message, Object data)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">RspBean</span>(<span class="hljs-number">500</span>, message, data);<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure>

<h2 id="登录后返回token"><a href="#登录后返回token" class="headerlink" title="登录后返回token"></a>登录后返回token</h2><ul>
<li>controller层</li>
<li>service层</li>
<li>pojo</li>
</ul>
<h4 id="实体对象"><a href="#实体对象" class="headerlink" title="实体对象"></a>实体对象</h4><ul>
<li>AdminLogin</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Data</span><br><span class="hljs-meta">@EqualsAndHashCode(callSuper = false)</span>  <span class="hljs-comment">//表示生成equals和hashCode方法时不考虑父类的属性</span><br><span class="hljs-meta">@Accessors(chain = true)</span>  <span class="hljs-comment">//表示启用链式编程风格，即通过返回当前对象来实现多个操作的连续调用</span><br><span class="hljs-meta">@ApiModel(value = &quot;AdminLogin对象&quot;, description = &quot;&quot;)</span>  <span class="hljs-comment">//描述一个对象的模型</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">AdminLogin</span> &#123;<br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;用户名&quot;, required = true)</span>  <span class="hljs-comment">//用于生成API文档时显示参数信息</span><br>    <span class="hljs-keyword">private</span> String username;<br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;密码&quot;, required = true)</span>  <span class="hljs-comment">//用于生成API文档时显示参数信息</span><br>    <span class="hljs-keyword">private</span> String password;<br>&#125;<br></code></pre></td></tr></table></figure>

<ul>
<li>Admin</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Data</span><br><span class="hljs-meta">@EqualsAndHashCode(callSuper = false)</span><br><span class="hljs-meta">@TableName(&quot;t_admin&quot;)</span><br><span class="hljs-meta">@ApiModel(value = &quot;Admin对象&quot;, description = &quot;&quot;)</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Admin</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">Serializable</span>, UserDetails &#123;<br><br>    <span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> <span class="hljs-type">long</span> <span class="hljs-variable">serialVersionUID</span> <span class="hljs-operator">=</span> <span class="hljs-number">1L</span>;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;id&quot;)</span><br>    <span class="hljs-meta">@TableId(value = &quot;id&quot;, type = IdType.AUTO)</span><br>    <span class="hljs-keyword">private</span> Integer id;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;姓名&quot;)</span><br>    <span class="hljs-keyword">private</span> String name;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;手机号码&quot;)</span><br>    <span class="hljs-keyword">private</span> String phone;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;住宅电话&quot;)</span><br>    <span class="hljs-keyword">private</span> String telephone;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;联系地址&quot;)</span><br>    <span class="hljs-keyword">private</span> String address;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;是否启用&quot;)</span><br>    <span class="hljs-keyword">private</span> Boolean enabled;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;用户名&quot;)</span><br>    <span class="hljs-keyword">private</span> String username;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;密码&quot;)</span><br>    <span class="hljs-keyword">private</span> String password;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;用户头像&quot;)</span><br>    <span class="hljs-keyword">private</span> String userFace;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;备注&quot;)</span><br>    <span class="hljs-keyword">private</span> String remark;<br><br>    <span class="hljs-meta">@ApiModelProperty(value = &quot;角色/权限&quot;)</span><br>    <span class="hljs-meta">@TableField(exist = false)</span><br>    <span class="hljs-keyword">private</span> List&lt;Role&gt; roles;<br><br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Collection&lt;? <span class="hljs-keyword">extends</span> <span class="hljs-title class_">GrantedAuthority</span>&gt; getAuthorities() &#123;<br>        List&lt;SimpleGrantedAuthority&gt; authorityList = roles<br>                .stream()<br>                .map(role -&gt; <span class="hljs-keyword">new</span> <span class="hljs-title class_">SimpleGrantedAuthority</span>(role.getName()))<br>                .collect(Collectors.toList());<br>        <span class="hljs-keyword">return</span> authorityList;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">isAccountNonExpired</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">isAccountNonLocked</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">isCredentialsNonExpired</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">true</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">isEnabled</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> enabled;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>



<h4 id="controller"><a href="#controller" class="headerlink" title="controller"></a>controller</h4><ul>
<li>调用adminService的login方法，传入实体对象AdminLogin与HttpServletRequest</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@ApiOperation(value = &quot;登录后返回token&quot;)</span><br><span class="hljs-meta">@PostMapping(&quot;/login&quot;)</span><br><span class="hljs-keyword">public</span> RspBean <span class="hljs-title function_">login</span><span class="hljs-params">(<span class="hljs-meta">@RequestBody</span> AdminLogin adminLogin, HttpServletRequest request)</span> &#123;<br>    <span class="hljs-keyword">return</span> adminService.login(adminLogin.getUsername(), adminLogin.getPassword(), request);<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="service"><a href="#service" class="headerlink" title="service"></a>service</h4><ul>
<li>userDetailsService接口：用于从外部数据源（如数据库）获取用户信息和权限信息</li>
<li>实现逻辑是用userDetailsService的loadUserByUsername方法，把用户名从数据源中获取用户信息，并将其封装为一个UserDetails对象返回，UserDetails对象包含了用户名、密码、角色等信息，并且可以自定义扩展其他字段</li>
<li>只需要调用loadUserByUsername并传入就可以从数据库获取到内容</li>
</ul>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 登陆后返回token</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> username</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> password</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> request</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">public</span> RspBean <span class="hljs-title function_">login</span><span class="hljs-params">(String username, String password, HttpServletRequest request)</span> &#123;<br>    <span class="hljs-comment">//获取到userDetails</span><br>    <span class="hljs-type">UserDetails</span> <span class="hljs-variable">userDetails</span> <span class="hljs-operator">=</span> userDetailsService.loadUserByUsername(username);<br>    System.out.println(userDetails.getPassword());<br>    <span class="hljs-comment">//判断userDetails是否为空，密码是否正确，账号是否启用</span><br>    <span class="hljs-keyword">if</span> (<span class="hljs-literal">null</span> == userDetails || passwordEncoder.matches(password, userDetails.getPassword())) &#123;<br>        <span class="hljs-keyword">return</span> RspBean.error(<span class="hljs-string">&quot;用户名密码不正确&quot;</span>);<br>    &#125;<br>    <span class="hljs-keyword">if</span> (!userDetails.isEnabled()) &#123;<br>        <span class="hljs-keyword">return</span> RspBean.error(<span class="hljs-string">&quot;账号未启用&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-comment">//更新security到全局</span><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 这段代码是使用Spring Security的身份验证机制，将用户的详细信息、空凭证和权限设置为一个身份验证令牌，并将其设置为当前安全上下文的身份验证。</span><br><span class="hljs-comment">     * 这样可以确保在后续的请求中，系统能够正确地识别已经通过身份验证的用户并授权其访问相应的资源</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-type">UsernamePasswordAuthenticationToken</span> <span class="hljs-variable">authenticationToken</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">UsernamePasswordAuthenticationToken</span>(userDetails, <span class="hljs-literal">null</span>, userDetails.getAuthorities());<br>    SecurityContextHolder.getContext().setAuthentication(authenticationToken);<br><br>    <span class="hljs-comment">//生成token</span><br>    <span class="hljs-type">String</span> <span class="hljs-variable">token</span> <span class="hljs-operator">=</span> jwtTokenUtil.generateToken(userDetails);<br>    Map&lt;String, String&gt; tokenMap = <span class="hljs-keyword">new</span> <span class="hljs-title class_">HashMap</span>&lt;&gt;();<br>    tokenMap.put(<span class="hljs-string">&quot;token&quot;</span>, token);<br>    tokenMap.put(<span class="hljs-string">&quot;tokenHead&quot;</span>, tokenHead);<br>    <span class="hljs-keyword">return</span> RspBean.success(<span class="hljs-string">&quot;登录成功&quot;</span>, tokenMap);<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="config"><a href="#config" class="headerlink" title="config"></a>config</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * protected void configure(AuthenticationManagerBuilder auth)：</span><br><span class="hljs-comment"> * 这个方法是用来配置AuthenticationManagerBuilder对象，它负责构建AuthenticationManager对象，用于处理用户认证。</span><br><span class="hljs-comment"> * &lt;p&gt;</span><br><span class="hljs-comment"> * throws Exception：这个方法可能会抛出异常，需要在调用该方法的地方进行异常处理。</span><br><span class="hljs-comment"> * &lt;p&gt;</span><br><span class="hljs-comment"> * auth.userDetailsService(userDetailsService())：这个方法指定了一个UserDetailsService实现类的实例，用于加载用户信息。</span><br><span class="hljs-comment"> * &lt;p&gt;</span><br><span class="hljs-comment"> * passwordEncoder()：这个方法返回一个PasswordEncoder实现类的实例，用于对用户密码进行编码和解码。</span><br><span class="hljs-comment"> * &lt;p&gt;</span><br><span class="hljs-comment"> * 总之，这段代码的作用是通过userDetailsService()方法加载用户信息，并使用passwordEncoder()方法对用户密码进行加密，</span><br><span class="hljs-comment"> * 从而构建一个AuthenticationManager对象，用于处理用户认证。</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> auth</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@throws</span> Exception</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">configure</span><span class="hljs-params">(AuthenticationManagerBuilder auth)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>    auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());<br>&#125;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> http</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@throws</span> Exception</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>    <span class="hljs-comment">//使用jwt不需要使用csrf</span><br>    http.csrf().disable()  <span class="hljs-comment">//禁用跨域请求伪造保护，因为此处采用了 JWT 方式进行认证</span><br>            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)  <span class="hljs-comment">//禁用 session，因为使用 JWT 进行认证，不需要记录用户会话状态</span><br>            .and()<br>            .authorizeRequests()  <span class="hljs-comment">//基于请求授权访问</span><br>            <span class="hljs-comment">//允许登录访问</span><br>            .anyRequest().authenticated()  <span class="hljs-comment">//除了上面所有请求都要拦截对除 /login 和 /logout 之外的所有请求进行身份验证</span><br>            <span class="hljs-comment">//动态权限配置</span><br>            .withObjectPostProcessor(<span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectPostProcessor</span>&lt;FilterSecurityInterceptor&gt;() &#123;<br>                <span class="hljs-meta">@Override</span><br>                <span class="hljs-keyword">public</span> &lt;O <span class="hljs-keyword">extends</span> <span class="hljs-title class_">FilterSecurityInterceptor</span>&gt; O <span class="hljs-title function_">postProcess</span><span class="hljs-params">(O object)</span> &#123;<br>                    object.setAccessDecisionManager(customUrlDecisionManage);<br>                    object.setSecurityMetadataSource(customFilter);<br>                    <span class="hljs-keyword">return</span> object;<br>                &#125;<br>            &#125;)<br>            .and()<br>            .headers().cacheControl(); <span class="hljs-comment">//在响应头中添加缓存控制指令，以避免浏览器缓存敏感数据</span><br><br>    <span class="hljs-comment">//添加登录授权</span><br>    http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);<br>    <span class="hljs-comment">//自定义返回类型</span><br>    http.exceptionHandling()<br>            .accessDeniedHandler(restfulAccessDeniedHandler)<br>            .authenticationEntryPoint(restAuthorizationEntryPoint);<br>&#125;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 在应用程序中，我们可以使用该PasswordEncoder将用户输入的密码进行加密，然后将其存储到数据库中。</span><br><span class="hljs-comment"> * 当用户登录时，我们可以使用该PasswordEncoder将用户输入的密码与存储在数据库中的加密密码进行比较，以验证用户身份</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Bean</span><br><span class="hljs-keyword">public</span> PasswordEncoder <span class="hljs-title function_">passwordEncoder</span><span class="hljs-params">()</span> &#123;<br>    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">BCryptPasswordEncoder</span>();<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="获取当前用户信息"><a href="#获取当前用户信息" class="headerlink" title="获取当前用户信息"></a>获取当前用户信息</h2><h4 id="controller-1"><a href="#controller-1" class="headerlink" title="controller"></a>controller</h4><p>正常调用service层方法进行查询</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@ApiOperation(value = &quot;获取当前登录用户信息&quot;)</span><br><span class="hljs-meta">@GetMapping(&quot;/admin/info&quot;)</span><br><span class="hljs-keyword">public</span> RspBean <span class="hljs-title function_">getUserInfo</span><span class="hljs-params">(Principal principal)</span> &#123;<br>    <span class="hljs-keyword">if</span> (<span class="hljs-literal">null</span> == principal) &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>    &#125;<br>    <span class="hljs-type">String</span> <span class="hljs-variable">username</span> <span class="hljs-operator">=</span> principal.getName();<br>    <span class="hljs-type">Admin</span> <span class="hljs-variable">admin</span> <span class="hljs-operator">=</span> adminService.getAdminByUsername(username);<br>    admin.setPassword(<span class="hljs-literal">null</span>);<br>    <span class="hljs-comment">//返回角色列表信息</span><br>    <span class="hljs-type">Integer</span> <span class="hljs-variable">adminId</span> <span class="hljs-operator">=</span> admin.getId();<br>    List&lt;Role&gt; roles = adminService.getRoles(adminId);<br>    admin.setRoles(roles);<br>    <span class="hljs-keyword">return</span> RspBean.success(<span class="hljs-string">&quot;获取成功&quot;</span>, admin);<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="service-1"><a href="#service-1" class="headerlink" title="service"></a>service</h4><p>使用mybatis框架自带的selectOne方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 从数据库中获取用户信息</span><br><span class="hljs-comment"> *</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> username</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">public</span> Admin <span class="hljs-title function_">getAdminByUsername</span><span class="hljs-params">(String username)</span> &#123;<br>    <span class="hljs-type">Admin</span> <span class="hljs-variable">admin</span> <span class="hljs-operator">=</span> adminMapper.selectOne(<span class="hljs-keyword">new</span> <span class="hljs-title class_">QueryWrapper</span>&lt;Admin&gt;().eq(<span class="hljs-string">&quot;username&quot;</span>, username).eq(<span class="hljs-string">&quot;enabled&quot;</span>, <span class="hljs-literal">true</span>));<br>    <span class="hljs-keyword">return</span> admin;<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="配置security授权登录过滤器"><a href="#配置security授权登录过滤器" class="headerlink" title="配置security授权登录过滤器"></a>配置security授权登录过滤器</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> com.czr.utils.JwtTokenUtil;<br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;<br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Value;<br><span class="hljs-keyword">import</span> org.springframework.security.authentication.UsernamePasswordAuthenticationToken;<br><span class="hljs-keyword">import</span> org.springframework.security.core.context.SecurityContextHolder;<br><span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UserDetails;<br><span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UserDetailsService;<br><span class="hljs-keyword">import</span> org.springframework.security.web.authentication.WebAuthenticationDetailsSource;<br><span class="hljs-keyword">import</span> org.springframework.web.filter.OncePerRequestFilter;<br><br><span class="hljs-keyword">import</span> javax.servlet.FilterChain;<br><span class="hljs-keyword">import</span> javax.servlet.ServletException;<br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest;<br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse;<br><span class="hljs-keyword">import</span> java.io.IOException;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * JWT授权过滤器</span><br><span class="hljs-comment"> */</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">JwtAuthenticationTokenFilter</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">OncePerRequestFilter</span> &#123;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> JwtTokenUtil jwtTokenUtil;<br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> UserDetailsService userDetailsService;<br>    <span class="hljs-meta">@Value(&quot;$&#123;jwt.tokenHeader&#125;&quot;)</span><br>    <span class="hljs-keyword">private</span> String tokenHeader;<br>    <span class="hljs-meta">@Value(&quot;$&#123;jwt.tokenHead&#125;&quot;)</span><br>    <span class="hljs-keyword">private</span> String tokenHead;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 这段代码是一个过滤器，在Spring Security框架中，用于对HTTP请求进行拦截和处理。主要功能是从请求头中获取token并校验其有效性，如果有效则把用户信息放入安全上下文中，以便后续的鉴权操作</span><br><span class="hljs-comment">     * 首先从request中取出请求头(tokenHeader)的值，判断是否为null且是否以指定的前缀(tokenHead)开头，如果是，则说明该请求需要进行认证</span><br><span class="hljs-comment">     * 从token中解析出用户名这段代码是一个Spring Security的过滤器，在处理HTTP请求时会对请求头中的token进行验证，如果token有效且合法，则将用户信息保存在SecurityContext中</span><br><span class="hljs-comment">     */</span><br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">doFilterInternal</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)</span> <span class="hljs-keyword">throws</span> ServletException, IOException &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">header</span> <span class="hljs-operator">=</span> request.getHeader(tokenHeader);  <span class="hljs-comment">//从HTTP请求头中获取名为tokenHeader的值，这个值表示token的名称</span><br>        System.out.println(request.getHeaderNames());<br>        <span class="hljs-keyword">if</span> (<span class="hljs-literal">null</span> != header &amp;&amp; header.startsWith(tokenHead)) &#123;  <span class="hljs-comment">//判断是否有token，并检查token的开头是否与tokenHead相同</span><br>            <span class="hljs-type">String</span> <span class="hljs-variable">token</span> <span class="hljs-operator">=</span> header.substring(tokenHead.length());  <span class="hljs-comment">//从token字符串中截取掉tokenHead，得到真正的token</span><br>            <span class="hljs-type">String</span> <span class="hljs-variable">username</span> <span class="hljs-operator">=</span> jwtTokenUtil.getUserNameFormToken(token);  <span class="hljs-comment">//使用JWT工具类从token中解析出用户名</span><br>            <span class="hljs-keyword">if</span> (<span class="hljs-literal">null</span> != username &amp;&amp; <span class="hljs-literal">null</span> == SecurityContextHolder.getContext().getAuthentication()) &#123;  <span class="hljs-comment">//判断当前SecurityContext中是否已经认证过，如果没有认证过则继续执行以下步骤</span><br>                <span class="hljs-type">UserDetails</span> <span class="hljs-variable">userDetails</span> <span class="hljs-operator">=</span> userDetailsService.loadUserByUsername(username);  <span class="hljs-comment">//通过用户名从用户详情服务中获取用户信息</span><br>                <span class="hljs-keyword">if</span> (jwtTokenUtil.validateToken(token, userDetails)) &#123;  <span class="hljs-comment">//使用JWT工具类验证token的有效性和合法性</span><br>                    <span class="hljs-comment">//创建一个认证令牌，包含了用户信息和权限信息</span><br>                    <span class="hljs-type">UsernamePasswordAuthenticationToken</span> <span class="hljs-variable">authenticationToken</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">UsernamePasswordAuthenticationToken</span>(userDetails, <span class="hljs-literal">null</span>, userDetails.getAuthorities());<br>                    authenticationToken.setDetails(<span class="hljs-keyword">new</span> <span class="hljs-title class_">WebAuthenticationDetailsSource</span>().buildDetails(request));  <span class="hljs-comment">//将请求对象设置为认证令牌的详细信息</span><br>                    SecurityContextHolder.getContext().setAuthentication(authenticationToken);  <span class="hljs-comment">//将认证令牌保存在SecurityContext中，这样后续操作就可以使用SecurityContext中的用户信息和权限信息了</span><br>                &#125;<br>            &#125;<br>        &#125;<br>        filterChain.doFilter(request, response);  <span class="hljs-comment">//调用下一个过滤器或者目标资源来处理HTTP请求和响应</span><br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure>

<h4 id="配置中添加过滤器"><a href="#配置中添加过滤器" class="headerlink" title="配置中添加过滤器"></a>配置中添加过滤器</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@param</span> http</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@throws</span> Exception</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br><br>    <span class="hljs-comment">//添加登录授权</span><br>    http.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);<br>    <br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="security自定义返回结果"><a href="#security自定义返回结果" class="headerlink" title="security自定义返回结果"></a>security自定义返回结果</h2><h4 id="认证失败处理器"><a href="#认证失败处理器" class="headerlink" title="认证失败处理器"></a>认证失败处理器</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">package</span> com.czr.config;<br><br><span class="hljs-keyword">import</span> com.czr.common.RspBean;<br><span class="hljs-keyword">import</span> com.fasterxml.jackson.databind.ObjectMapper;<br><span class="hljs-keyword">import</span> org.springframework.security.core.AuthenticationException;<br><span class="hljs-keyword">import</span> org.springframework.security.web.AuthenticationEntryPoint;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Component;<br><br><span class="hljs-keyword">import</span> javax.servlet.ServletException;<br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest;<br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse;<br><span class="hljs-keyword">import</span> java.io.IOException;<br><span class="hljs-keyword">import</span> java.io.PrintWriter;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * 认证失败处理器</span><br><span class="hljs-comment"> * 当未登录或者token失效时，自定义返回结果</span><br><span class="hljs-comment"> */</span><br><span class="hljs-meta">@Component</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">RestAuthorizationEntryPoint</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">AuthenticationEntryPoint</span> &#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">commence</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)</span> <span class="hljs-keyword">throws</span> IOException, ServletException &#123;<br>        response.setCharacterEncoding(<span class="hljs-string">&quot;UTF-8&quot;</span>);  <span class="hljs-comment">//设置响应编码为UTF-8，保证返回的json字符串不会出现乱码</span><br>        response.setContentType(<span class="hljs-string">&quot;application/json&quot;</span>);  <span class="hljs-comment">//设置响应类型为JSON格式，告诉浏览器返回的数据是JSON格式的数据</span><br>        <span class="hljs-type">PrintWriter</span> <span class="hljs-variable">writer</span> <span class="hljs-operator">=</span> response.getWriter();  <span class="hljs-comment">//获取响应输出流对象，用于向客户端发送响应数据</span><br>        <span class="hljs-type">RspBean</span> <span class="hljs-variable">bean</span> <span class="hljs-operator">=</span> RspBean.error(<span class="hljs-string">&quot;尚未登录，请先登录！&quot;</span>);  <span class="hljs-comment">//创建一个RspBean对象，并将错误信息设置为“权限不足！”</span><br>        bean.setCode(<span class="hljs-number">401</span>);  <span class="hljs-comment">//设置HTTP状态码为401，表示未授权访问</span><br>        writer.write(<span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectMapper</span>().writeValueAsString(bean));  <span class="hljs-comment">//使用Jackson库中的ObjectMapper对象将bean对象转换为JSON格式的字符串</span><br>        writer.flush();  <span class="hljs-comment">//使用Jackson库中的ObjectMapper对象将bean对象转换为JSON格式的字符串</span><br>        writer.close();  <span class="hljs-comment">//关闭输出流并刷新缓冲区，确保响应数据已经成功发送给客户端</span><br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure>

<h4 id="授权失败处理器"><a href="#授权失败处理器" class="headerlink" title="授权失败处理器"></a>授权失败处理器</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> com.czr.common.RspBean;<br><span class="hljs-keyword">import</span> com.fasterxml.jackson.databind.ObjectMapper;<br><span class="hljs-keyword">import</span> org.springframework.security.access.AccessDeniedException;<br><span class="hljs-keyword">import</span> org.springframework.security.web.access.AccessDeniedHandler;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Component;<br><br><span class="hljs-keyword">import</span> javax.servlet.ServletException;<br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletRequest;<br><span class="hljs-keyword">import</span> javax.servlet.http.HttpServletResponse;<br><span class="hljs-keyword">import</span> java.io.IOException;<br><span class="hljs-keyword">import</span> java.io.PrintWriter;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> czr</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@version</span> v1.0.0</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Package</span> : com.czr.config</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Description</span> : 当访问接口没有权限时，自定义返回结果</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Create</span> on : 2023/5/18 13:50</span><br><span class="hljs-comment"> **/</span><br><span class="hljs-meta">@Component</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">RestfulAccessDeniedHandler</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">AccessDeniedHandler</span> &#123;<br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">handle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException)</span> <span class="hljs-keyword">throws</span> IOException, ServletException &#123;<br>        response.setCharacterEncoding(<span class="hljs-string">&quot;UTF-8&quot;</span>);<br>        response.setContentType(<span class="hljs-string">&quot;application/json&quot;</span>);<br>        <span class="hljs-type">PrintWriter</span> <span class="hljs-variable">writer</span> <span class="hljs-operator">=</span> response.getWriter();<br>        <span class="hljs-type">RspBean</span> <span class="hljs-variable">bean</span> <span class="hljs-operator">=</span> RspBean.error(<span class="hljs-string">&quot;权限不足，请联系管理员&quot;</span>);<br>        bean.setCode(<span class="hljs-number">403</span>);<br>        writer.write(<span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectMapper</span>().writeValueAsString(bean));<br>        writer.flush();<br>        writer.close();<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h4 id="Security配置类"><a href="#Security配置类" class="headerlink" title="Security配置类"></a>Security配置类</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-meta">@Override</span><br><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>    <span class="hljs-comment">//自定义返回类型</span><br>    http.exceptionHandling()<br>            .accessDeniedHandler(restfulAccessDeniedHandler)<br>            .authenticationEntryPoint(restAuthorizationEntryPoint);<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="swagger2配置并添加Authorize"><a href="#swagger2配置并添加Authorize" class="headerlink" title="swagger2配置并添加Authorize"></a>swagger2配置并添加Authorize</h2><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;<br><span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;<br><span class="hljs-keyword">import</span> springfox.documentation.builders.ApiInfoBuilder;<br><span class="hljs-keyword">import</span> springfox.documentation.builders.PathSelectors;<br><span class="hljs-keyword">import</span> springfox.documentation.builders.RequestHandlerSelectors;<br><span class="hljs-keyword">import</span> springfox.documentation.service.*;<br><span class="hljs-keyword">import</span> springfox.documentation.spi.DocumentationType;<br><span class="hljs-keyword">import</span> springfox.documentation.spi.service.contexts.SecurityContext;<br><span class="hljs-keyword">import</span> springfox.documentation.spring.web.plugins.Docket;<br><span class="hljs-keyword">import</span> springfox.documentation.swagger2.annotations.EnableSwagger2;<br><br><span class="hljs-keyword">import</span> java.util.ArrayList;<br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> czr</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@version</span> v1.0.0</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Package</span> : com.czr.config</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Description</span> : Swagger2配置类</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Create</span> on : 2023/5/18 14:41</span><br><span class="hljs-comment"> **/</span><br><span class="hljs-meta">@Configuration</span><br><span class="hljs-meta">@EnableSwagger2</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Swagger2Config</span> &#123;<br><br>    <span class="hljs-meta">@Bean</span><br>    <span class="hljs-keyword">public</span> Docket <span class="hljs-title function_">createRestApi</span><span class="hljs-params">()</span> &#123;  <span class="hljs-comment">//这个方法名可以任意取，它创建了一个Docket对象，该对象包含了Swagger的配置信息。</span><br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">Docket</span>(DocumentationType.SWAGGER_2)  <span class="hljs-comment">//Swagger的版本号，现在使用的是2.x版本。</span><br>                .apiInfo(apiInfo())  <span class="hljs-comment">//用来设置API文档的基本信息，比如标题、描述、版本等。其中 apiInfo() 方法返回一个 ApiInfo 对象，里面包含了这些基本信息。</span><br>                .select()  <span class="hljs-comment">//启动选择器。</span><br>                .apis(RequestHandlerSelectors.basePackage(<span class="hljs-string">&quot;com.czr.controller&quot;</span>))  <span class="hljs-comment">//指定扫描的包路径，只有该路径下的controller类中的接口才会生成API文档。</span><br>                .paths(PathSelectors.any())  <span class="hljs-comment">//指定对所有路径都进行监控和处理。</span><br>                .build()  <span class="hljs-comment">//创建Docket对象的最后一步，它将以上设置和规则应用到生成的文档中。</span><br>                .securityContexts(securityContexts())<br>                .securitySchemes(securitySchemes());<br>    &#125;<br><br>    <span class="hljs-keyword">private</span> ApiInfo <span class="hljs-title function_">apiInfo</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ApiInfoBuilder</span>()<br>                .title(<span class="hljs-string">&quot;接口文档&quot;</span>)<br>                .description(<span class="hljs-string">&quot;文档描述&quot;</span>)<br>                .contact(<span class="hljs-keyword">new</span> <span class="hljs-title class_">Contact</span>(<span class="hljs-string">&quot;czr&quot;</span>, <span class="hljs-string">&quot;http://localhost:8888/doc.html&quot;</span>, <span class="hljs-string">&quot;647900765&quot;</span>))<br><span class="hljs-comment">//                .licenseUrl(&quot;http://localhost:8888/doc.html&quot;)</span><br>                .version(<span class="hljs-string">&quot;1.0&quot;</span>)<br>                .build();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 在 Swagger 文档中配置安全方案的方法</span><br><span class="hljs-comment">     * 这段代码定义了一个名为 &quot;Authorization&quot; 的安全方案，使用 header 头部传递认证信息。</span><br><span class="hljs-comment">     * 其中，&quot;Authorization&quot; 是该安全方案的名称，在后续的 API 定义中会用到；&quot;header&quot; 表示认证信息将放置在 HTTP 请求头的 header 中。</span><br><span class="hljs-comment">     * &lt;p&gt;</span><br><span class="hljs-comment">     * 最后，该方法返回一个 List 集合，其中包含上述定义的 ApiKey 对象，表示该 API 文档中支持的所有安全方案。</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> List&lt;ApiKey&gt; <span class="hljs-title function_">securitySchemes</span><span class="hljs-params">()</span> &#123;<br>        List&lt;ApiKey&gt; result = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();<br>        <span class="hljs-type">ApiKey</span> <span class="hljs-variable">apiKey</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">ApiKey</span>(<span class="hljs-string">&quot;Authorization&quot;</span>, <span class="hljs-string">&quot;Authorization&quot;</span>, <span class="hljs-string">&quot;header&quot;</span>);<br>        result.add(apiKey);<br>        <span class="hljs-keyword">return</span> result;<br>    &#125;<br><br>    <span class="hljs-keyword">private</span> List&lt;SecurityContext&gt; <span class="hljs-title function_">securityContexts</span><span class="hljs-params">()</span> &#123;<br>        List&lt;SecurityContext&gt; result = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();  <span class="hljs-comment">//创建了一个空的ArrayList，用于存储SecurityContext对象，并将其赋值给result变量</span><br>        result.add(getContextByPath(<span class="hljs-string">&quot;/hello/.*&quot;</span>));  <span class="hljs-comment">//调用getContextByPath方法，并将返回的SecurityContext对象添加到result中。</span><br>        <span class="hljs-keyword">return</span> result;  <span class="hljs-comment">//返回包含SecurityContext对象的List</span><br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 用于存储安全相关的上下文信息，比如当前登录用户的信息</span><br><span class="hljs-comment">     * 此处的 securityContexts() 方法返回一个列表，其中包含一个 SecurityContext 对象，该对象通过调用 getContextByPath(&quot;/hello/.*) 方法得到</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> pathRegex</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> SecurityContext <span class="hljs-title function_">getContextByPath</span><span class="hljs-params">(String pathRegex)</span> &#123;<br>        <span class="hljs-keyword">return</span> SecurityContext.builder()<br>                .securityReferences(defaulAuth())<br>                .forPaths(PathSelectors.regex(pathRegex))<br>                .build();<br>    &#125;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * 用于生成默认的API接口权限认证列表</span><br><span class="hljs-comment">     *</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@return</span></span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-keyword">private</span> List&lt;SecurityReference&gt; <span class="hljs-title function_">defaulAuth</span><span class="hljs-params">()</span> &#123;<br>        List&lt;SecurityReference&gt; result = <span class="hljs-keyword">new</span> <span class="hljs-title class_">ArrayList</span>&lt;&gt;();  <span class="hljs-comment">//定义一个空的 List&lt;SecurityReference&gt; 对象，用于存放生成的权限认证列表</span><br>        <span class="hljs-type">AuthorizationScope</span> <span class="hljs-variable">AuthorizationScope</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AuthorizationScope</span>(<span class="hljs-string">&quot;global&quot;</span>, <span class="hljs-string">&quot;all&quot;</span>);  <span class="hljs-comment">//创建一个 AuthorizationScope 对象，该对象表示接口调用所需要的权限范围。在本例中，&quot;global&quot; 表示全局权限，&quot;all&quot; 则表示拥有该权限的用户可以访问所有的接口</span><br>        AuthorizationScope[] AuthorizationScopes = <span class="hljs-keyword">new</span> <span class="hljs-title class_">AuthorizationScope</span>[<span class="hljs-number">1</span>];<br>        AuthorizationScopes[<span class="hljs-number">0</span>] = AuthorizationScope;  <span class="hljs-comment">//创建一个 AuthorizationScope 数组对象 AuthorizationScopes，并将刚才创建的 AuthorizationScope 对象添加到数组中</span><br>        result.add(<span class="hljs-keyword">new</span> <span class="hljs-title class_">SecurityReference</span>(<span class="hljs-string">&quot;Authorization&quot;</span>, AuthorizationScopes));  <span class="hljs-comment">//将刚才创建的 SecurityReference 对象添加到 result 中，并返回 result</span><br>        <span class="hljs-keyword">return</span> result;<br>    &#125;<br>&#125;<br></code></pre></td></tr></table></figure>

<h2 id="根据请求URL判断角色，判断用户角色"><a href="#根据请求URL判断角色，判断用户角色" class="headerlink" title="根据请求URL判断角色，判断用户角色"></a>根据请求URL判断角色，判断用户角色</h2><ul>
<li>CustomFilter（判断用户角色）</li>
<li>CustomUrlDecisionManage（根据请求判断角色）</li>
<li>SecurityConfig</li>
</ul>
<h4 id="CustomFilter"><a href="#CustomFilter" class="headerlink" title="CustomFilter"></a>CustomFilter</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> com.czr.pojo.Menu;<br><span class="hljs-keyword">import</span> com.czr.pojo.Role;<br><span class="hljs-keyword">import</span> com.czr.service.IMenuService;<br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;<br><span class="hljs-keyword">import</span> org.springframework.security.access.ConfigAttribute;<br><span class="hljs-keyword">import</span> org.springframework.security.access.SecurityConfig;<br><span class="hljs-keyword">import</span> org.springframework.security.web.FilterInvocation;<br><span class="hljs-keyword">import</span> org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Component;<br><span class="hljs-keyword">import</span> org.springframework.util.AntPathMatcher;<br><br><span class="hljs-keyword">import</span> java.util.Collection;<br><span class="hljs-keyword">import</span> java.util.List;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> czr</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@version</span> v1.0.0</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Package</span> : com.czr.filter</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Description</span> : 根据请求的url分析所需要的角色</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Create</span> on : 2023/5/22 14:29</span><br><span class="hljs-comment"> **/</span><br><span class="hljs-meta">@Component</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">CustomFilter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">FilterInvocationSecurityMetadataSource</span> &#123;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> IMenuService menuService;<br><br>    <span class="hljs-type">AntPathMatcher</span> <span class="hljs-variable">antPathMatcher</span> <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AntPathMatcher</span>();<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Collection&lt;ConfigAttribute&gt; <span class="hljs-title function_">getAttributes</span><span class="hljs-params">(Object object)</span> <span class="hljs-keyword">throws</span> IllegalArgumentException &#123;<br>        <span class="hljs-type">String</span> <span class="hljs-variable">requestUrl</span> <span class="hljs-operator">=</span> ((FilterInvocation) object).getRequestUrl(); <span class="hljs-comment">//从传入的参数 object 中获取当前请求的URL</span><br>        List&lt;Menu&gt; menus = menuService.getMenusWithRole();  <span class="hljs-comment">//从数据库或其他数据源中获取所有菜单及其对应的角色信息</span><br>        <span class="hljs-keyword">for</span> (Menu menu : menus) &#123;<br>            <span class="hljs-keyword">if</span> (antPathMatcher.match(menu.getUrl(), requestUrl)) &#123;<br>                String[] strings = menu.getRoles().stream().map(Role::getName).toArray(String[]::<span class="hljs-keyword">new</span>);  <span class="hljs-comment">//将该菜单所需要的角色转换为字符串数组</span><br>                <span class="hljs-keyword">return</span> SecurityConfig.createList(strings);  <span class="hljs-comment">// 并返回包含这些角色的 SecurityConfig 对象列表</span><br>            &#125;<br>        &#125;<br>        <span class="hljs-comment">//如果url与所有角色都不匹配，就分配一个默认的角色</span><br>        <span class="hljs-keyword">return</span> SecurityConfig.createList(<span class="hljs-string">&quot;ROLE_LOGIN&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> Collection&lt;ConfigAttribute&gt; <span class="hljs-title function_">getAllConfigAttributes</span><span class="hljs-params">()</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">null</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">supports</span><span class="hljs-params">(Class&lt;?&gt; clazz)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure>

<h4 id="CustomUrlDecisionManage"><a href="#CustomUrlDecisionManage" class="headerlink" title="CustomUrlDecisionManage"></a>CustomUrlDecisionManage</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> org.springframework.security.access.AccessDecisionManager;<br><span class="hljs-keyword">import</span> org.springframework.security.access.AccessDeniedException;<br><span class="hljs-keyword">import</span> org.springframework.security.access.ConfigAttribute;<br><span class="hljs-keyword">import</span> org.springframework.security.authentication.AnonymousAuthenticationToken;<br><span class="hljs-keyword">import</span> org.springframework.security.authentication.InsufficientAuthenticationException;<br><span class="hljs-keyword">import</span> org.springframework.security.core.Authentication;<br><span class="hljs-keyword">import</span> org.springframework.security.core.GrantedAuthority;<br><span class="hljs-keyword">import</span> org.springframework.stereotype.Component;<br><br><span class="hljs-keyword">import</span> java.util.Collection;<br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@author</span> czr</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@version</span> v1.0.0</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Package</span> : com.czr.filter</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Description</span> : 权限控制，判断用户角色</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Create</span> on : 2023/5/22 15:15</span><br><span class="hljs-comment"> **/</span><br><span class="hljs-meta">@Component</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">CustomUrlDecisionManage</span> <span class="hljs-keyword">implements</span> <span class="hljs-title class_">AccessDecisionManager</span> &#123;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">decide</span><span class="hljs-params">(Authentication authentication, Object object, Collection&lt;ConfigAttribute&gt; configAttributes)</span> <span class="hljs-keyword">throws</span> AccessDeniedException, InsufficientAuthenticationException &#123;<br>        <span class="hljs-keyword">for</span> (ConfigAttribute attribute : configAttributes) &#123;<br>            <span class="hljs-comment">//当前url所需要的角色</span><br>            <span class="hljs-type">String</span> <span class="hljs-variable">needRole</span> <span class="hljs-operator">=</span> attribute.getAttribute();<br>            <span class="hljs-comment">//判断是否是登录即可访问的角色，此角色在CustomFilter中设置</span><br>            <span class="hljs-keyword">if</span> (<span class="hljs-string">&quot;ROLE_LOGIN&quot;</span>.equals(needRole)) &#123;<br>                <span class="hljs-keyword">if</span> (authentication <span class="hljs-keyword">instanceof</span> AnonymousAuthenticationToken) &#123;<br>                    <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AccessDeniedException</span>(<span class="hljs-string">&quot;尚未登陆，请登录&quot;</span>);<br>                &#125; <span class="hljs-keyword">else</span> &#123;<br>                    <span class="hljs-keyword">return</span>;<br>                &#125;<br>            &#125;<br>            <span class="hljs-comment">//判断用户角色是否是url所需要的角色</span><br>            Collection&lt;? <span class="hljs-keyword">extends</span> <span class="hljs-title class_">GrantedAuthority</span>&gt; authorities = authentication.getAuthorities();<br>            <span class="hljs-keyword">for</span> (GrantedAuthority authority : authorities) &#123;<br>                <span class="hljs-keyword">if</span> (authority.getAuthority().equals(needRole)) &#123;<br>                    <span class="hljs-keyword">return</span>;<br>                &#125;<br>            &#125;<br>        &#125;<br>        <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> <span class="hljs-title class_">AccessDeniedException</span>(<span class="hljs-string">&quot;权限不足&quot;</span>);<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">supports</span><span class="hljs-params">(ConfigAttribute attribute)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>    &#125;<br><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">public</span> <span class="hljs-type">boolean</span> <span class="hljs-title function_">supports</span><span class="hljs-params">(Class&lt;?&gt; clazz)</span> &#123;<br>        <span class="hljs-keyword">return</span> <span class="hljs-literal">false</span>;<br>    &#125;<br>&#125;<br><br></code></pre></td></tr></table></figure>

<h4 id="SecurityConfig"><a href="#SecurityConfig" class="headerlink" title="SecurityConfig"></a>SecurityConfig</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br></pre></td><td class="code"><pre><code class="hljs java"><span class="hljs-keyword">import</span> com.czr.filter.CustomFilter;<br><span class="hljs-keyword">import</span> com.czr.filter.CustomUrlDecisionManage;<br><span class="hljs-keyword">import</span> com.czr.filter.JwtAuthenticationTokenFilter;<br><span class="hljs-keyword">import</span> com.czr.pojo.Admin;<br><span class="hljs-keyword">import</span> com.czr.service.IAdminService;<br><span class="hljs-keyword">import</span> org.springframework.beans.factory.annotation.Autowired;<br><span class="hljs-keyword">import</span> org.springframework.context.annotation.Bean;<br><span class="hljs-keyword">import</span> org.springframework.context.annotation.Configuration;<br><span class="hljs-keyword">import</span> org.springframework.security.config.annotation.ObjectPostProcessor;<br><span class="hljs-keyword">import</span> org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;<br><span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.builders.HttpSecurity;<br><span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.builders.WebSecurity;<br><span class="hljs-keyword">import</span> org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;<br><span class="hljs-keyword">import</span> org.springframework.security.config.http.SessionCreationPolicy;<br><span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UserDetailsService;<br><span class="hljs-keyword">import</span> org.springframework.security.core.userdetails.UsernameNotFoundException;<br><span class="hljs-keyword">import</span> org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;<br><span class="hljs-keyword">import</span> org.springframework.security.crypto.password.PasswordEncoder;<br><span class="hljs-keyword">import</span> org.springframework.security.web.access.intercept.FilterSecurityInterceptor;<br><span class="hljs-keyword">import</span> org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;<br><br><br><span class="hljs-comment">/**</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Configuration</span> 是一种注解，用于标记一个类为Spring应用程序上下文中的bean定义提供者。</span><br><span class="hljs-comment"> * 通常，使用<span class="hljs-doctag">@Configuration</span>注解的类也会使用<span class="hljs-doctag">@Bean</span>注解来声明需要创建的bean，并且可以使用其他注解来配置bean的属性。</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Configuration</span> 类可以包含多个<span class="hljs-doctag">@Bean</span>方法，每个方法都对应于一个bean定义。</span><br><span class="hljs-comment"> * 在这些方法中，可以根据需要进行任何必要的初始化和配置，并返回一个实例化的bean对象。</span><br><span class="hljs-comment"> * <span class="hljs-doctag">@Configuration</span> 类还可以使用<span class="hljs-doctag">@Import</span>注解来导入其他<span class="hljs-doctag">@Configuration</span>类，以便将它们的bean定义合并到同一个应用程序上下文中。</span><br><span class="hljs-comment"> * 此外，可以使用<span class="hljs-doctag">@Profile</span>注解来指定特定的配置文件或环境下才会生效的bean定义</span><br><span class="hljs-comment"> */</span><br><br><span class="hljs-meta">@Configuration</span><br><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">SecurityConfig</span> <span class="hljs-keyword">extends</span> <span class="hljs-title class_">WebSecurityConfigurerAdapter</span> &#123;<br><br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> CustomFilter customFilter;<br>    <span class="hljs-meta">@Autowired</span><br>    <span class="hljs-keyword">private</span> CustomUrlDecisionManage customUrlDecisionManage;<br><br>    <span class="hljs-comment">/**</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@param</span> http</span><br><span class="hljs-comment">     * <span class="hljs-doctag">@throws</span> Exception</span><br><span class="hljs-comment">     */</span><br>    <span class="hljs-meta">@Override</span><br>    <span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">configure</span><span class="hljs-params">(HttpSecurity http)</span> <span class="hljs-keyword">throws</span> Exception &#123;<br>        <span class="hljs-comment">//使用jwt不需要使用csrf</span><br>        http.csrf().disable()  <span class="hljs-comment">//禁用跨域请求伪造保护，因为此处采用了 JWT 方式进行认证</span><br>                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)  <span class="hljs-comment">//禁用 session，因为使用 JWT 进行认证，不需要记录用户会话状态</span><br>                .and()<br>                .authorizeRequests()  <span class="hljs-comment">//基于请求授权访问</span><br>                <span class="hljs-comment">//允许登录访问</span><br>                .anyRequest().authenticated()  <span class="hljs-comment">//除了上面所有请求都要拦截对除 /login 和 /logout 之外的所有请求进行身份验证</span><br>                <span class="hljs-comment">//动态权限配置</span><br>                .withObjectPostProcessor(<span class="hljs-keyword">new</span> <span class="hljs-title class_">ObjectPostProcessor</span>&lt;FilterSecurityInterceptor&gt;() &#123;<br>                    <span class="hljs-meta">@Override</span><br>                    <span class="hljs-keyword">public</span> &lt;O <span class="hljs-keyword">extends</span> <span class="hljs-title class_">FilterSecurityInterceptor</span>&gt; O <span class="hljs-title function_">postProcess</span><span class="hljs-params">(O object)</span> &#123;<br>                        object.setAccessDecisionManager(customUrlDecisionManage);<br>                        object.setSecurityMetadataSource(customFilter);<br>                        <span class="hljs-keyword">return</span> object;<br>                    &#125;<br>                &#125;)<br>                .and()<br>                .headers().cacheControl(); <span class="hljs-comment">//在响应头中添加缓存控制指令，以避免浏览器缓存敏感数据</span><br><br>&#125;<br><br></code></pre></td></tr></table></figure>


                
              </div>
            
            <hr/>
            <div>
              <div class="post-metas my-3">
  
  
    <div class="post-meta">
      <i class="iconfont icon-tags"></i>
      
        <a href="/tags/yeb/">#yeb</a>
      
    </div>
  
</div>


              
  

  <div class="license-box my-3">
    <div class="license-title">
      <div>认证授权</div>
      <div>http://czrgitee.gitee.io/2023/05/23/认证授权/</div>
    </div>
    <div class="license-meta">
      
        <div class="license-meta-item">
          <div>作者</div>
          <div>czr</div>
        </div>
      
      
        <div class="license-meta-item license-meta-date">
          <div>发布于</div>
          <div>2023年5月23日</div>
        </div>
      
      
      
        <div class="license-meta-item">
          <div>许可协议</div>
          <div>
            
              
              
                <a target="_blank" href="https://creativecommons.org/licenses/by/4.0/">
                  <span class="hint--top hint--rounded" aria-label="BY - 署名">
                    <i class="iconfont icon-by"></i>
                  </span>
                </a>
              
            
          </div>
        </div>
      
    </div>
    <div class="license-icon iconfont"></div>
  </div>



              
                <div class="post-prevnext my-3">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2023/05/24/%E5%85%B3%E4%BA%8Ehexo%E5%92%8Cfluid%E7%A2%B0%E5%88%B0%E7%9A%84%E9%97%AE%E9%A2%98/" title="关于hexo和fluid碰到的问题">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">关于hexo和fluid碰到的问题</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2023/05/22/%E4%BB%A3%E7%A0%81%E7%94%9F%E6%88%90%E5%99%A8/" title="代码生成器">
                        <span class="hidden-mobile">代码生成器</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>

    <div class="side-col d-none d-lg-block col-lg-2">
      
  <aside class="sidebar" style="margin-left: -1rem">
    <div id="toc">
  <p class="toc-header">
    <i class="iconfont icon-list"></i>
    <span>目录</span>
  </p>
  <div class="toc-body" id="toc-body"></div>
</div>



  </aside>


    </div>
  </div>
</div>





  



  



  



  



  







    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v" for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>

    

    
  </main>

  <footer>
    <div class="footer-inner">
  
    <div class="footer-content">
       <a href="https://hexo.io" target="_blank" rel="nofollow noopener"><span>Andersen</span></a> <i class="iconfont icon-love"></i> <a href="https://github.com/fluid-dev/hexo-theme-fluid" target="_blank" rel="nofollow noopener"><span>blog</span></a> 
    </div>
  
  
  
  
</div>

  </footer>

  <!-- Scripts -->
  
  <script  src="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://lib.baomitu.com/nprogress/0.2.0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://lib.baomitu.com/jquery/3.6.0/jquery.min.js" ></script>
<script  src="https://lib.baomitu.com/twitter-bootstrap/4.6.1/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>


  <script  src="https://lib.baomitu.com/typed.js/2.0.12/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var subtitle = document.getElementById('subtitle');
      if (!subtitle || !typing) {
        return;
      }
      var text = subtitle.getAttribute('data-typed-text');
      
        typing(text);
      
    })(window, document);
  </script>




  
    <script  src="/js/img-lazyload.js" ></script>
  




  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/tocbot/4.18.2/tocbot.min.js', function() {
    var toc = jQuery('#toc');
    if (toc.length === 0 || !window.tocbot) { return; }
    var boardCtn = jQuery('#board-ctn');
    var boardTop = boardCtn.offset().top;

    window.tocbot.init(Object.assign({
      tocSelector     : '#toc-body',
      contentSelector : '.markdown-body',
      linkClass       : 'tocbot-link',
      activeLinkClass : 'tocbot-active-link',
      listClass       : 'tocbot-list',
      isCollapsedClass: 'tocbot-is-collapsed',
      collapsibleClass: 'tocbot-is-collapsible',
      scrollSmooth    : true,
      includeTitleTags: true,
      headingsOffset  : -boardTop,
    }, CONFIG.toc));
    if (toc.find('.toc-list-item').length > 0) {
      toc.css('visibility', 'visible');
    }

    Fluid.events.registerRefreshCallback(function() {
      if ('tocbot' in window) {
        tocbot.refresh();
        var toc = jQuery('#toc');
        if (toc.length === 0 || !tocbot) {
          return;
        }
        if (toc.find('.toc-list-item').length > 0) {
          toc.css('visibility', 'visible');
        }
      }
    });
  });
</script>


  <script src=https://lib.baomitu.com/clipboard.js/2.0.10/clipboard.min.js></script>

  <script>Fluid.plugins.codeWidget();</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/anchor-js/4.3.1/anchor.min.js', function() {
    window.anchors.options = {
      placement: CONFIG.anchorjs.placement,
      visible  : CONFIG.anchorjs.visible
    };
    if (CONFIG.anchorjs.icon) {
      window.anchors.options.icon = CONFIG.anchorjs.icon;
    }
    var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
    var res = [];
    for (var item of el) {
      res.push('.markdown-body > ' + item.trim());
    }
    if (CONFIG.anchorjs.placement === 'left') {
      window.anchors.options.class = 'anchorjs-link-left';
    }
    window.anchors.add(res.join(', '));

    Fluid.events.registerRefreshCallback(function() {
      if ('anchors' in window) {
        anchors.removeAll();
        var el = (CONFIG.anchorjs.element || 'h1,h2,h3,h4,h5,h6').split(',');
        var res = [];
        for (var item of el) {
          res.push('.markdown-body > ' + item.trim());
        }
        if (CONFIG.anchorjs.placement === 'left') {
          anchors.options.class = 'anchorjs-link-left';
        }
        anchors.add(res.join(', '));
      }
    });
  });
</script>


  
<script>
  Fluid.utils.createScript('https://lib.baomitu.com/fancybox/3.5.7/jquery.fancybox.min.js', function() {
    Fluid.plugins.fancyBox();
  });
</script>


  <script>Fluid.plugins.imageCaption();</script>

  <script  src="/js/local-search.js" ></script>





<!-- 主题的启动项，将它保持在最底部 -->
<!-- the boot of the theme, keep it at the bottom -->
<script  src="/js/boot.js" ></script>


  

  <noscript>
    <div class="noscript-warning">博客在允许 JavaScript 运行的环境下浏览效果更佳</div>
  </noscript>
</body>
</html>
